using System;
using System.Collections.Generic;
using System.Linq;
using Urs.Core;
using Urs.Core.Caching;
using Urs.Core.Data;
using Urs.Plugin.Shipping.ByWeight.Domain;

namespace Urs.Plugin.Shipping.ByWeight.Services
{
    public partial class ShippingByWeightService : IShippingByWeightService
    {
        #region Constants
        private const string SHIPPINGBYWEIGHT_ALL_KEY = "urs.shippingbyweight.all-{0}-{1}";
        private const string SHIPPINGBYWEIGHT_PATTERN_KEY = "urs.shippingbyweight.";
        #endregion

        #region Fields

        private readonly IRepository<ShippingByWeightRecord> _sbwRepository;
        private readonly IRepository<ShippingScopeByWeightRecord> _sbwrdcRepository;
        private readonly ICacheManager _cacheManager;

        #endregion

        #region Ctor

        public ShippingByWeightService(ICacheManager cacheManager,
            IRepository<ShippingByWeightRecord> sbwRepository,
            IRepository<ShippingScopeByWeightRecord> sbwrdcRepository)
        {
            this._cacheManager = cacheManager;
            this._sbwRepository = sbwRepository;
            this._sbwrdcRepository = sbwrdcRepository;
        }

        #endregion

        #region Shipping


        public virtual void DeleteShippingByWeightRecord(ShippingByWeightRecord shippingByWeightRecord)
        {
            if (shippingByWeightRecord == null)
                throw new ArgumentNullException("shippingByWeightRecord");

            _sbwRepository.Delete(shippingByWeightRecord);

            _cacheManager.RemoveByPattern(SHIPPINGBYWEIGHT_PATTERN_KEY);
        }

        public virtual IPagedList<ShippingByWeightRecord> GetAll(int pageIndex = 0, int pageSize = int.MaxValue)
        {
            string key = string.Format(SHIPPINGBYWEIGHT_ALL_KEY, pageIndex, pageSize);
            return _cacheManager.Get(key, () =>
            {
                var query = from sbw in _sbwRepository.Table
                            orderby sbw.ShippingMethodId, sbw.First
                            select sbw;

                var records = new PagedList<ShippingByWeightRecord>(query, pageIndex, pageSize);
                return records;
            });
        }

        public virtual ShippingByWeightRecord FindRecord(int shippingMethodId, string provinceCode, string cityCode, decimal weight)
        {
            //filter by weight and shipping method
            var existingRecords = GetAll().Where(sbw => sbw.ShippingMethodId == shippingMethodId)
                .ToList();

            var sbyr = new ShippingByWeightRecord();
            foreach (var item in existingRecords)
            {
                var query = item.Scopes;

                query = query.Where(x => x.ProvinceCode == provinceCode).ToList();
                if (!string.IsNullOrEmpty(cityCode))
                    query = query.Where(x => x.CityCode == cityCode).ToList();

                var record = query.FirstOrDefault();
                if (record != null)
                {
                    sbyr = item;
                    break;
                }
            }

            if (sbyr.Id == 0)
            {
                var defaultItem = existingRecords.Where(q => q.Scopes.Count == 0).FirstOrDefault();
                if (defaultItem != null)
                    sbyr = defaultItem;
            }
            return sbyr;
        }

        public virtual ShippingByWeightRecord GetById(int shippingByWeightRecordId)
        {
            if (shippingByWeightRecordId == 0)
                return null;

            var record = _sbwRepository.GetById(shippingByWeightRecordId);
            return record;
        }

        public virtual void InsertShippingByWeightRecord(ShippingByWeightRecord shippingByWeightRecord)
        {
            if (shippingByWeightRecord == null)
                throw new ArgumentNullException("shippingByWeightRecord");

            _sbwRepository.Insert(shippingByWeightRecord);

            _cacheManager.RemoveByPattern(SHIPPINGBYWEIGHT_PATTERN_KEY);
        }

        public virtual void UpdateShippingByWeightRecord(ShippingByWeightRecord shippingByWeightRecord)
        {
            if (shippingByWeightRecord == null)
                throw new ArgumentNullException("shippingByWeightRecord");

            _sbwRepository.Update(shippingByWeightRecord);

            _cacheManager.RemoveByPattern(SHIPPINGBYWEIGHT_PATTERN_KEY);
        }

        #endregion

        #region ShippingScopes

        public void InsertShippingScope(ShippingScopeByWeightRecord entity)
        {
            if (entity == null)
                throw new ArgumentNullException("shippingScopeByWeightRecord is null");

            _sbwrdcRepository.Insert(entity);
        }

        public IList<ShippingScopeByWeightRecord> GetScopesByPieceRecordId(int shippingByWeightRecordId)
        {
            return _sbwrdcRepository.Table
                .Where(x => x.ShippingByWeightRecordId == shippingByWeightRecordId)
                .ToList();
        }

        public void DeleteShippingScope(ShippingScopeByWeightRecord entity)
        {
            if (entity == null)
                throw new ArgumentNullException("shippingScopeByWeightRecord is null");

            _sbwrdcRepository.Delete(entity);
        }

        #endregion

    }
}
